/*
    $Header: /Windows/Shell/ShellExt.root/ShellExt/src/CPropSht.cpp 2     08-07-24 0:20 Ken $
    $Log: /Windows/Shell/ShellExt.root/ShellExt/src/CPropSht.cpp $
 * 
 * 2     08-07-24 0:20 Ken
 * add hook key (inject.dll setwindowshookex)
 * 
 * 1     08-01-05 0:08 Ken
*/

// ..\Src\CPropSht.cpp : Implementation of CPropSht

#include "stdafx.h"
#include "..\Src\CPropSht.h"
#include "CShellExtModule.h"
#include "Misc.h"

#pragma comment(lib, "comctl32.lib")

extern HINSTANCE g_hInstance;
extern CShellExtModule _AtlModule;

// CPropSht

BOOL CPropSht::VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad/*called by Load*/ )
{
    ATLASSERT(m_cstrSrc.IsEmpty());

    DWORD dwFlg;
    if( (FALSE==GetVlmFlg(pszFl, &dwFlg))
        || (0==((FILE_SUPPORTS_REPARSE_POINTS|FILE_NAMED_STREAMS)&dwFlg)) )
    {
        return FALSE;
    }

    if(FILE_ATTRIBUTE_DIRECTORY&GetFileAttributes(pszFl))
    {
        m_junct.Initialize(pszFl);
    }

    HANDLE hFl=CreateFile( pszFl, 0, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_READ, NULL
                                        , OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0 );
    if(INVALID_HANDLE_VALUE!=hFl)
    {
        if(FALSE==GetFileInformationByHandle(hFl,&m_flinfo))
        {
            ATLTRACE(_T("GetFileInformationByHandle faild!\r\n"));
            return FALSE;
        }
        CloseHandle(hFl);
    }

    m_cstrSrc=pszFl;
    return TRUE;
}

HRESULT CPropSht::AddPages ( LPFNADDPROPSHEETPAGE lpfnAddPageProc, LPARAM lParam )
{
    PROPSHEETPAGE psp;
    psp.dwSize = sizeof(PROPSHEETPAGE);
    psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_DEFAULT | PSP_USEICONID | PSP_USECALLBACK;
    psp.hInstance = g_hInstance;
    psp.pszIcon = NULL;
    psp.pszTitle = TEXT("ExtInfo");
    psp.lParam = reinterpret_cast<LPARAM>(this);
    psp.pfnCallback = PropPageCallbackProc;
    psp.pcRefParent = (UINT*)&_AtlModule.m_nLockCnt;
    psp.pfnDlgProc = PropPageDlgProc;
    psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_EXTINFO);

    HPROPSHEETPAGE hPage = CreatePropertySheetPage ( &psp );
    if ( NULL != hPage )
    {
        if ( !lpfnAddPageProc ( hPage, lParam ))
        {
            DestroyPropertySheetPage ( hPage );
        }
    }

    // to prevent this module release, for this class will used later
    AddRef();
    return S_OK;
}

UINT CALLBACK CPropSht::PropPageCallbackProc ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp )
{
    if ( PSPCB_RELEASE == uMsg )
    {
        CPropSht* pThis=reinterpret_cast<CPropSht*>(ppsp->lParam);
        pThis->Release();
    }
    return 1;
}


BOOL CALLBACK CPropSht::PropPageDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    BOOL bRet=FALSE;
    TCHAR szTgt[MAX_PATH];

    PROPSHEETPAGE*  ppsp;
    CPropSht* pThis;

    switch ( uMsg )
    {
    case WM_INITDIALOG:
        //4 ! note lParam is the PROPSHEETPAGE.lParam set in AddPages when WM_INITDIALOG,
        //4 store this para
        ppsp = (PROPSHEETPAGE*) lParam;
        SetWindowLong ( hwnd, GWL_USERDATA, (LONG)(ppsp->lParam) );
        pThis=reinterpret_cast<CPropSht*>(ppsp->lParam);
        bRet = pThis->OnInitDialog ( hwnd, lParam );
        break;

    case WM_COMMAND:
        pThis=reinterpret_cast<CPropSht*>(GetWindowLong ( hwnd, GWL_USERDATA ));
        switch (LOWORD (wParam))
        {
        //
        // junction commands
        //
        case IDC_BUTTON_SETTGT:
            if(FALSE!=GetOpenFolderName(szTgt, ARRAYOF(szTgt), hwnd, TEXT("Please select junction target:")))
            {
                SetWindowText(GetDlgItem(hwnd, IDC_EDIT_JUNCTTGT), szTgt);
                SendMessage ( GetParent(hwnd), PSM_CHANGED, (WPARAM) hwnd, 0 );
            }
            break;

        case IDC_EDIT_JUNCTTGT:
            if(EN_CHANGE==HIWORD(wParam))
            {
                SendMessage ( GetParent(hwnd), PSM_CHANGED, (WPARAM) hwnd, 0 );
            }
            break;

        //
        // stream commands
        //
        case IDC_BUTTON_NEW:
            if(FALSE!=pThis->OnNewStrm(hwnd))
            {
                pThis->OnStrmSelChg(hwnd);
            }
            break;

        case IDC_BUTTON_DEL:
            if(FALSE!=pThis->OnDelStrm(hwnd))
            {
                pThis->OnStrmSelChg(hwnd);
            }
            break;

        case IDC_BUTTON_WRT2FL:
            pThis->OnWrt2Fl(hwnd);
            break;

        case IDC_BUTTON_WRT2STRM:
            if(FALSE!=pThis->OnWrt2Strm(hwnd))
            {
                pThis->OnStrmSelChg(hwnd);
            }
            break;

        case IDC_COMBO_STRM:
            if(CBN_SELCHANGE==HIWORD(wParam))
            {
                pThis->OnStrmSelChg(hwnd);
            }
            break;

        default:
            break;
        }
        break;

        case WM_NOTIFY:
            pThis=reinterpret_cast<CPropSht*>(GetWindowLong ( hwnd, GWL_USERDATA ));
            switch ( ((NMHDR*)(lParam))->code )
            {
                case PSN_APPLY:
                bRet = pThis->OnJunctApply(hwnd, (PSHNOTIFY*)(lParam) );
                break;

            }
            break;

        default:
            break;
    }
    return bRet;
}

BOOL CPropSht::OnInitDialog ( HWND hwnd, LPARAM lParam )
{
    //
    // set file attribute
    //
    CString szTmp;
    szTmp.Format(_T("Attribute:0x%x"),m_flinfo.dwFileAttributes);
    SetWindowText(GetDlgItem(hwnd, IDC_STATIC_ATTR), szTmp);

    szTmp.Format(_T("LnkNum:0x%x"),m_flinfo.nNumberOfLinks);
    SetWindowText(GetDlgItem(hwnd, IDC_STATIC_LNKNUM), szTmp);

    szTmp.Format(_T("Id(H):0x%x"),m_flinfo.nFileIndexHigh);
    SetWindowText(GetDlgItem(hwnd, IDC_STATIC_IDH), szTmp);

    szTmp.Format(_T("Id(L):0x%x"),m_flinfo.nFileIndexLow);
    SetWindowText(GetDlgItem(hwnd, IDC_STATIC_IDL), szTmp);

    //
    // stream
    //
    FillStrmBox(hwnd);
    if(0==SendMessage(GetDlgItem(hwnd, IDC_COMBO_STRM), CB_GETCOUNT, 0, 0))
    {
        EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_DEL), FALSE);
        EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2FL), FALSE);
        EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2STRM), FALSE);
    }
    else
    {
        SendMessage(GetDlgItem(hwnd, IDC_COMBO_STRM), CB_SETCURSEL, 0, 0);
        OnStrmSelChg(hwnd);
    }

    // show junction part
    if( (NULL!=m_junct.GetJunctionTgt())
        || (TRUE==IsEmptyDir(m_cstrSrc)) )    // a empty dir
    {
        SetWindowText(GetDlgItem(hwnd, IDC_STATIC_JUNCTNAME), m_junct.GetJunctionName());
        SetWindowText(GetDlgItem(hwnd, IDC_STATIC_JUNCTTP), m_junct.GetJunctionTypeName());
        SetWindowText(GetDlgItem(hwnd, IDC_EDIT_JUNCTTGT), m_junct.GetJunctionTgt());
        if(FALSE==PathFileExists(m_junct.GetJunctionTgt()))
        {
            SetWindowText(GetDlgItem(hwnd, IDC_STATIC_TGTNOEXIST), TEXT("!Target not exist!"));
        }
    }
    // hid junction part
    else
    {
        ShowWindow(GetDlgItem(hwnd, IDC_STATIC_JUNCTNAME), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_STATIC_JUNCTTP), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_EDIT_JUNCTTGT), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_STATIC_TGTNOEXIST), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_BUTTON_SETTGT), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_STATIC_J_TYPE), SW_HIDE);
        ShowWindow(GetDlgItem(hwnd, IDC_STATIC_J_TGT), SW_HIDE);
    }
    return FALSE;                       // Take the default focus handling.
}


BOOL CPropSht::OnJunctApply ( HWND hwnd, PSHNOTIFY* phdr )
{
    TCHAR szJuntTgt[MAX_PATH];
    GetWindowText(GetDlgItem(hwnd,IDC_EDIT_JUNCTTGT), szJuntTgt, ARRAYOF(szJuntTgt));
    if(0==szJuntTgt[0])
        return TRUE;
    if( (NULL==m_junct.GetJunctionTgt())
        || (0 !=_tcscmp(szJuntTgt, m_junct.GetJunctionTgt())) )
    {
        if(PathFileExists(szJuntTgt))
        {
            CJunction NewJunct(m_junct);
            if(FALSE==CJunction::CreateJunction(m_junct.GetJunctionName(),szJuntTgt, TRUE))
            {
                MessageBox(hwnd, TEXT("Can't create junction!"), TEXT("Create junction error!"), MB_OK);
            }
        }
        else
        {
            MessageBox(hwnd, TEXT("Junction target not exist!"), TEXT("Create junction error!"), MB_OK);
        }
    }

    return TRUE;
}

VOID CPropSht::FillStrmBox(HWND hwnd)
{
    if(FALSE==m_strm.BegEnum(m_cstrSrc.GetBuffer()))
    {
        ATLTRACE(_T("BegEnum faild!\r\n"));
        return;
    }

    // Fill out the listbox
    DWORD    dwNameSize;
    TCHAR    szStmName[MAX_PATH];
    HWND    hWndLst=GetDlgItem(hwnd, IDC_COMBO_STRM);
    SendMessage(hWndLst, LB_RESETCONTENT, 0, 0);
    while(FALSE!=m_strm.Next(&dwNameSize, NULL))
    {
        if(0!=dwNameSize)
        {
            m_strm.GetName(szStmName, sizeof(szStmName)/sizeof(szStmName[0]));
            SendMessage(hWndLst, CB_ADDSTRING, 0, (LPARAM)szStmName);
        }
    }
    m_strm.EndEnum();
}



BOOL CPropSht::OnNewStrm(HWND hwnd)
{
    TCHAR    szName[MAX_PATH];
    CString    cstrMsg;
    HWND    hWndCmb=GetDlgItem(hwnd, IDC_COMBO_STRM);
    if(0!=GetWindowText(GetDlgItem(hwnd, IDC_COMBO_STRM), szName, ARRAYOF(szName)))
    {
        if(CB_ERR==SendMessage(hWndCmb, CB_FINDSTRING, 0, (LPARAM)szName))
        {
            HANDLE hStrm=CStream::CreateStrm(m_cstrSrc.GetBuffer(), szName, 0, CREATE_NEW);
            if(INVALID_HANDLE_VALUE!=hStrm)
            {
                SendMessage(hWndCmb, CB_ADDSTRING, 0, (LPARAM)szName);
                CloseHandle(hStrm);
                if(0!=SendMessage(GetDlgItem(hwnd, IDC_COMBO_STRM), CB_GETCOUNT, 0, 0))
                {
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_DEL), TRUE);
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2FL), TRUE);
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2STRM), TRUE);
                }
                return TRUE;
            }
        }
        MessageBox(NULL, _T("Create stream faild!\r\n Maybe the stream had existed!"), NULL, MB_OK);
    }
    return FALSE;
}

BOOL CPropSht::OnDelStrm(HWND hwnd)
{
    TCHAR    szName[MAX_PATH];
    CString    cstrMsg;
    HWND    hWndCmb=GetDlgItem(hwnd, IDC_COMBO_STRM);
    if(0!=GetWindowText(GetDlgItem(hwnd, IDC_COMBO_STRM), szName, ARRAYOF(szName)))
    {
        int id=SendMessage(hWndCmb, CB_FINDSTRING, 0, (LPARAM)szName);
        if(CB_ERR!=id)
        {
            if(FALSE!=CStream::DelStrm(m_cstrSrc.GetBuffer(), szName))
            {
                SendMessage(hWndCmb, CB_DELETESTRING, id, 0);
                SendMessage(hWndCmb, CB_SETCURSEL, 0, 0);
                if(0==SendMessage(GetDlgItem(hwnd, IDC_COMBO_STRM), CB_GETCOUNT, 0, 0))
                {
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_DEL), FALSE);
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2FL), FALSE);
                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_WRT2STRM), FALSE);
                }
                return TRUE;
            }
        }
        MessageBox(NULL, _T("Delete stream faild!\r\n Maybe the stream not exist!"), NULL, MB_OK);
    }
    return FALSE;
}

BOOL CPropSht::OnWrt2Fl(HWND hwnd)
{
    TCHAR    szName[MAX_PATH];
    CString    cstrMsg;
    HWND    hWndCmb=GetDlgItem(hwnd, IDC_COMBO_STRM);
    if(0!=GetWindowText(GetDlgItem(hwnd, IDC_COMBO_STRM), szName, ARRAYOF(szName)))
    {
        if(CB_ERR!=SendMessage(hWndCmb, CB_FINDSTRING, 0, (LPARAM)szName))
        {
            // get file to write
            TCHAR    szFl[MAX_PATH];
            // Set szFl[0] to '\0' so that GetOpenFileName does not use the contents of szFile to initialize itself.
            szFl[0]=0;
            OPENFILENAME opf;
            ZeroMemory(&opf, sizeof(opf));
            opf.lStructSize=sizeof(opf);
            opf.hwndOwner=hwnd;
            opf.Flags=0;
            opf.lpstrFile=szFl;
            opf.nMaxFile=ARRAYOF(szFl);
            if(FALSE==GetOpenFileName(&opf))
            {
                return TRUE;
            }
            HANDLE hFl=CreateFile(szFl, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
            if(INVALID_HANDLE_VALUE==hFl)
            {
                MessageBox(hwnd, _T("Can't open file to write!"), NULL, MB_OK);
                return FALSE;
            }
            if(BST_CHECKED==IsDlgButtonChecked(hwnd, IDC_CHECK_APPEN))
            {
                SetFilePointer(hFl, 0, 0, FILE_END);
            }

            //open stream
            HANDLE hStrm=CStream::CreateStrm(m_cstrSrc.GetBuffer(), szName, GENERIC_READ, OPEN_ALWAYS);
            if(INVALID_HANDLE_VALUE==hStrm)
            {
                MessageBox(NULL, _T("Write stream to file faild!\r\n Maybe the stream not exist!"), NULL, MB_OK);
                CloseHandle(hFl);
                return FALSE;
            }

            BOOL fRet=TRUE;
            BYTE bBuf[1024];
            DWORD dwRdLen, dwWtLen;
            while( (TRUE==ReadFile(hStrm, bBuf, sizeof(bBuf), &dwRdLen, NULL))
                    && (0!=dwRdLen) )
            {
                if( (FALSE==WriteFile(hFl, bBuf, dwRdLen, &dwWtLen, NULL))
                    || (dwRdLen!=dwWtLen) )
                {
                    MessageBox(NULL, _T("Write stream to file error!"), NULL, MB_OK);
                    fRet=FALSE;
                    break;
                }
            }
            CloseHandle(hFl);
            CloseHandle(hStrm);
            return fRet;
        }
    }
    return FALSE;
}

BOOL CPropSht::OnWrt2Strm(HWND hwnd)
{
    TCHAR    szName[MAX_PATH];
    CString    cstrMsg;
    HWND    hWndCmb=GetDlgItem(hwnd, IDC_COMBO_STRM);
    if(0!=GetWindowText(GetDlgItem(hwnd, IDC_COMBO_STRM), szName, ARRAYOF(szName)))
    {
        int id=SendMessage(hWndCmb, CB_FINDSTRING, 0, (LPARAM)szName);
        if(CB_ERR!=id)
        {
            // get file to write
            TCHAR    szFl[MAX_PATH];
            // Set szFl[0] to '\0' so that GetOpenFileName does not use the contents of szFile to initialize itself.
            szFl[0]=0;
            OPENFILENAME opf;
            ZeroMemory(&opf, sizeof(opf));
            opf.lStructSize=sizeof(opf);
            opf.hwndOwner=hwnd;
            opf.Flags=OFN_FILEMUSTEXIST;
            opf.lpstrFile=szFl;
            opf.nMaxFile=ARRAYOF(szFl);
            if(FALSE==GetOpenFileName(&opf))
            {
                return TRUE;
            }
            HANDLE hFl=CreateFile(szFl, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
            if(INVALID_HANDLE_VALUE==hFl)
            {
                MessageBox(hwnd, _T("Can't open file to write!"), NULL, MB_OK);
                return FALSE;
            }

            //open stream
            HANDLE hStrm=CStream::CreateStrm(m_cstrSrc.GetBuffer(), szName, GENERIC_WRITE, OPEN_ALWAYS);
            if(INVALID_HANDLE_VALUE==hStrm)
            {
                MessageBox(NULL, _T("Write file to stream faild!\r\n Maybe the stream not exist!"), NULL, MB_OK);
                CloseHandle(hFl);
                return FALSE;
            }
            if(BST_CHECKED==IsDlgButtonChecked(hwnd, IDC_CHECK_APPEN))
            {
                SetFilePointer(hStrm, 0, 0, FILE_END);
            }


            BOOL fRet=TRUE;
            BYTE bBuf[1024];
            DWORD dwRdLen, dwWtLen;
            while( (TRUE==ReadFile(hFl, bBuf, sizeof(bBuf), &dwRdLen, NULL))
            && (0!=dwRdLen) )
            {
                if( (FALSE==WriteFile(hStrm, bBuf, dwRdLen, &dwWtLen, NULL))
                    || (dwRdLen!=dwWtLen) )
                {
                    MessageBox(NULL, _T("Write stream to file error!"), NULL, MB_OK);
                    fRet=FALSE;
                    break;
                }
            }
            CloseHandle(hFl);
            CloseHandle(hStrm);

            SendMessage(hWndCmb, CB_SETCURSEL, id, 0);    // select it
            return fRet;
        }
    }    return FALSE;
}

BOOL CPropSht::OnStrmSelChg(HWND hwnd)
{
    TCHAR    szName[MAX_PATH];
    HWND hCb=GetDlgItem(hwnd, IDC_COMBO_STRM);
    int iSel=SendMessage(hCb, CB_GETCURSEL, 0, 0);
    if(CB_ERR!=SendMessage(hCb, CB_GETLBTEXT, iSel, (LPARAM)(szName) ))
    {
        HANDLE hStrm=CStream::CreateStrm(m_cstrSrc.GetBuffer(), szName, GENERIC_READ, OPEN_EXISTING);
        ATLASSERT(INVALID_HANDLE_VALUE!=hStrm);
        {
            // read 1k content to display
            BYTE buf[1024];
            DWORD dwRdLen;
            if(FALSE!=ReadFile(hStrm, buf, sizeof(buf)-1, &dwRdLen, NULL))
            {
                buf[dwRdLen]=0;
                SetWindowText(GetDlgItem(hwnd, IDC_EDIT_STRMVIEW), (LPCSTR)(&buf));
            }
            CloseHandle(hStrm);
            return TRUE;
        }
    }

    SetWindowText(GetDlgItem(hwnd, IDC_EDIT_STRMVIEW), NULL);
    return TRUE;
}
